package edu.upol.paradise.hypervisor;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;

import edu.upol.paradise.hypervisor.NodeClusterList.NodeCluster;
import edu.upol.paradise.hypervisor.protocol.Packet;
import edu.upol.paradise.hypervisor.protocol.PingPacket;
import edu.upol.paradise.hypervisor.protocol.PongPacket;
import edu.upol.paradise.hypervisor.protocol.RequestCNLPacket;
import edu.upol.paradise.hypervisor.protocol.SendCNLPacket;
import edu.upol.paradise.hypervisor.protocol.ServicePacket;
import edu.upol.paradise.hypervisor.protocol.TCPConnector;
import edu.upol.paradise.utils.HypervisorUtils;

public class HypervisorServiceDaemon extends Thread {
	static final Logger log = Logger.getLogger(HypervisorServiceDaemon.class);
	
	private int requestPort;
	
	public HypervisorServiceDaemon(int serviceThreadCount, int requestPort) {
		super();
		this.requestPort = requestPort;
		setName("Paradise Hypervisor Service Daemon");
		setDaemon(true);
		pool = Executors.newFixedThreadPool(serviceThreadCount);
		start();
	}
	
	ExecutorService pool;
	
	@Override
	public void run(){
		try {
			log.debug("Starting hypervisor service daemon at: " + requestPort);
			
			@SuppressWarnings("resource")
			ServerSocket socket = new ServerSocket(requestPort);
			while (true){
				final Socket s = socket.accept();
				pool.execute(new Runnable(){

					public void run() {
						try {
							TCPConnector connector = new TCPConnector(s);
							Packet packet = connector.accept();
							ServicePacket sp = ServicePacket.asServicePacket(packet);
							if (sp == null)
								connector.terminate();
							else {
								handleServiceRequest(sp, connector);
								connector.terminate();
							}
						} catch (Exception e) {
							log.error(e);
							log.debug(e, e);
						}
					}
					
				});
			}
		} catch (IOException e) {
			log.error(e);
			log.debug(e, e);
		}
	}

	protected void handleServiceRequest(ServicePacket sp, TCPConnector connector) throws Exception {
		ParadiseHypervisor hypervisor = ParadiseHypervisor.hypervisor;
		if (sp instanceof PingPacket){
			PongPacket pp = new PongPacket();
			connector.send(pp);
		}
		if (sp instanceof RequestCNLPacket){
			List<NodeCluster> nodes = hypervisor.getNodes().getAllAsList();
			SendCNLPacket pp = new SendCNLPacket();
			for (NodeCluster node : nodes){
				if (node.isValid() && !HypervisorUtils.isLocalHost(node.addr))
					pp.add(node);
			}
			connector.send(pp);
		}
		
	}
}
